package org.springframework.beans.factory.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.StringValueResolver;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * bean工程的抽象实现类默认单例
 */
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {
    //存放所有bean后处理器
    private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

    //存放的key是单例的工厂bean的返回bean的名称 value是需要的工厂bean的getObject方法的返回对象
    private final Map<String, Object> factoryBeanObjectCache = new HashMap<>();

    //存放value解析器的map集合
    private final List<StringValueResolver> embeddedValueResolvers = new ArrayList<StringValueResolver>();

    //转换器的核心类
    private ConversionService conversionService;

    @Override
    public Object getBean(String name) throws BeansException {
        //从单例池里获取出来的bean可能是普通bean，也可能是工厂bean，但是工厂bean的名称是工厂bean返回的真正bean，不是自己的名称
        Object sharedInstance = getSingleton(name);
        if (sharedInstance != null) {
            //如果是FactoryBean，从FactoryBean#getObject中创建bean
            //如果是普通bean，则创建bean返回
            return getObjectForBeanInstance(sharedInstance, name);
        }
        //bean不存在根据bean定义对象创建bean
        BeanDefinition beanDefinition = getBeanDefinition(name);
        Object bean = createBean(name, beanDefinition);


        return getObjectForBeanInstance(bean, name);
    }

    /**
     * 如果是FactoryBean，从FactoryBean#getObject中创建bean
     * @param beanInstance
     * @param beanName
     * @return
     */
    protected Object getObjectForBeanInstance(Object beanInstance, String beanName) {
        Object result = beanInstance;
        //如果是FactoryBean，从FactoryBean#getObject中创建bean
        if(beanInstance instanceof FactoryBean){
            FactoryBean factoryBean = (FactoryBean) beanInstance;

            try {
                //判断工厂bean是否是单例的
                if(factoryBean.isSingleton()){
                    //单例的工厂bean，尝试从缓存中取出来
                    result = factoryBeanObjectCache.get(beanName);

                    //缓存里不存在，创建并且添加到缓存
                    if(result == null){
                        result = factoryBean.getObject();
                        this.factoryBeanObjectCache.put(beanName, result);
                    }
                }else {
                    //prototype作用域bean，新创建bean
                    result = factoryBean.getObject();
                }
            } catch (Exception ex) {
                throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", ex);
            }
        }

        //统一结果返回，不论是工厂bean还是普通bean
        return result;
    }

    /**
     * 根据名称和类型获取bean 但是其实用名称就可以获取了 可以转换类型为指定类型
     * @param name
     * @param requiredType
     * @return
     * @param <T>
     * @throws BeansException
     */
    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return (T) getBean(name);
    }

    /**
     * 是否包含bean
     * @param name
     * @return
     */
    @Override
    public boolean containsBean(String name) {
        return containsBeanDefinition(name);
    }

    protected abstract boolean containsBeanDefinition(String beanName);


    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;

    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        //存在一样的时候 先删除再添加 没有则删除不了
        this.beanPostProcessors.remove(beanPostProcessor);
        this.beanPostProcessors.add(beanPostProcessor);
    }

    public List<BeanPostProcessor> getBeanPostProcessors() {
        return this.beanPostProcessors;
    }

    /**
     * 添加解析器的方法
     * @param valueResolver
     */
    public void addEmbeddedValueResolver(StringValueResolver valueResolver) {
        this.embeddedValueResolvers.add(valueResolver);
    }

    /**
     * 执行解析的逻辑
     * @param value
     * @return
     */
    public String resolveEmbeddedValue(String value) {
        String result = value;
        //遍历所有的解析器 对值进行加工
        for (StringValueResolver resolver : this.embeddedValueResolvers) {
            result = resolver.resolveStringValue(result);
        }
        return result;
    }

    @Override
    public ConversionService getConversionService() {
        return conversionService;
    }

    @Override
    public void setConversionService(ConversionService conversionService) {
        this.conversionService = conversionService;
    }

}
